﻿
namespace JanusLibAing.AutoSave
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Xml;

    public class XmlStorage
    {
        public const string Encoding = "UTF-16";                      //MLHIDE

        private XmlDocument document = new XmlDocument();
        private string rootFolder = Path.GetTempPath();
        private List<IDataItem> items = new List<IDataItem>();
        private string fileExtension;
        private string storageFolder;

        private XmlStorageFactory itemsFactory = null;

        ManualResetEvent writeEntry = new ManualResetEvent(false);

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlStorage"/> class.
        /// </summary>
        /// <param name="storageFolder">The storage folder.</param>
        /// <param name="fileExtension">The file extension.</param>
        /// <param name="itemsFactory">The items factory.</param>
        public XmlStorage(string storageFolder, string fileExtension, XmlStorageFactory itemsFactory)
        {
            this.fileExtension = fileExtension;
            this.itemsFactory = itemsFactory;
            this.storageFolder = storageFolder;
        }


        /// <summary>
        /// Loads the specified file name.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public virtual void Load(string fileName)
        {
            string completeSavePath;

            string fullFileName = GetFullFileName(fileName, out completeSavePath);
            items.Clear();
            //string completeSavePath = Path.Combine(RootFolder, AutoSaveFolder);
            document.Load(fullFileName);
            XmlElement documentElement = document.DocumentElement;
            foreach (XmlElement node in documentElement.ChildNodes)
            {
                XmlAttribute xmlAttributeName = node.Attributes["name"]; //MLHIDE
                XmlAttribute xmlAttributeValue = node.Attributes["value"]; //MLHIDE
                IDataItem dataItem = itemsFactory.CreateDataItem(xmlAttributeName.Value, xmlAttributeValue.Value);
                items.Add(dataItem);
            }
        }

        /// <summary>
        /// Gets the full name of the file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="completeSavePath">The complete save path.</param>
        /// <returns></returns>
        protected string GetFullFileName(string fileName, out string completeSavePath)
        {

            string extension = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(extension))
            {
                extension = FileExtension;
            }
            else
            {
                // Clear extension for add
                extension = "";
            }

            completeSavePath = fileName;
            string fullFileName = fileName;

            if (!Path.IsPathRooted(fileName))
            {
                completeSavePath = Path.Combine(rootFolder, StorageFolder);
                fullFileName = Path.Combine(completeSavePath, fileName);
            }
            else
            {
                completeSavePath = Path.GetDirectoryName(completeSavePath);
            }
            fullFileName += extension;
            return fullFileName;
        }

        /// <summary>
        /// Writes the specified file name.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public virtual void Write(string fileName)
        {
            string completeSavePath;

            string fullFileName = GetFullFileName(fileName, out completeSavePath);

            // Protection from write in write;
            if (!writeEntry.WaitOne(500))
            {
                writeEntry.Set();
                try
                {
                    if (!Directory.Exists(completeSavePath))
                    {
                        DirectoryInfo directoryInfo = Directory.CreateDirectory(completeSavePath);
                    }

                    UnicodeEncoding encoding = new UnicodeEncoding();
                    XmlElement root = document.DocumentElement;

                    if (root == null)
                    {
                        XmlDeclaration xmlDeclaration = document.CreateXmlDeclaration(
                            "1.0", encoding.EncodingName, null);
                        //MLHIDE
                        document.AppendChild(xmlDeclaration);

                        root = document.CreateElement("AutoSave"); //MLHIDE
                        document.AppendChild(root);
                    }

                    root.RemoveAll();

                    foreach (IDataItem dataItem in items)
                    {
                        XmlElement xmlElement = document.CreateElement("item"); //MLHIDE
                        xmlElement.SetAttribute("name", dataItem.Name); //MLHIDE
                        xmlElement.SetAttribute("value", dataItem.ToString()); //MLHIDE
                        root.AppendChild(xmlElement);
                    }

                    using (XmlTextWriter writer = new XmlTextWriter(fullFileName, encoding))
                    {
                        writer.Formatting = Formatting.Indented;
                        //writer.Settings.Indent = true;
                        //writer.Settings.NewLineHandling = NewLineHandling.Replace;
                        document.WriteTo(writer);
                    }
                }
                finally
                {
                    writeEntry.Reset();
                }
            }
        }

        /// <summary>
        /// Gets the <see cref="JanusLibAing.AutoSave.IDataItem"/> at the specified index.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public IDataItem GetAt(int index)
        {
            return items[index];
        }

        /// <summary>
        /// Gets the <see cref="JanusLibAing.AutoSave.IDataItem"/> at the specified index.
        /// </summary>
        /// <value></value>
        public IDataItem this[int index]
        {
            get
            {
                return items[index];
            }
        }

        public IDataItem this[string key]
        {
            get
            {
                IDataItem ret = null;
                foreach (IDataItem dataItem in items)
                {
                    if (dataItem.Name == key)
                    {
                        ret = dataItem;
                        break;
                    }
                }
                return ret;
            }
        }

        /// <summary>
        /// Adds the item.
        /// </summary>
        /// <param name="item">The item.</param>
        public void AddItem(IDataItem item)
        {
            items.Add(item);
        }

        /// <summary>
        /// Gets the storage folder.
        /// </summary>
        /// <value>The storage folder.</value>
        public string StorageFolder
        {
            get { return storageFolder; }
        }

        /// <summary>
        /// Gets the file extension.
        /// </summary>
        /// <value>The file extension.</value>
        public string FileExtension
        {
            get { return fileExtension; }
        }

        /// <summary>
        /// Gets the item count.
        /// </summary>
        /// <value>The item count.</value>
        public int ItemCount
        {
            get { return items.Count; }
        }

        /// <summary>
        /// Gets or sets the root folder.
        /// </summary>
        /// <value>The root folder.</value>
        public string RootFolder
        {
            get { return rootFolder; }
            set { rootFolder = value; }
        }

    }
}